package org.mbds.wolf.seql;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;

/**
 * 
 * @author alesas
 * 
 * According the CONGFIG type and provided parameters, 
 * this class returns a singleton of the appropriate WOlf/SeQL controller
 *
 */
public class SeqlController 
{
	
	/*
	 * API CONFIG
	 */
	public static enum CONFIG 
	{
		ANDROID_HCE,
		ANDROID_OMAPI,
		ANDROID_IDGO800,
		PCSC_READER
	}
    
	private static SeqlController instance = null;
	
    private static HashMap<Object, ISeqlController> controllers = new HashMap<Object, ISeqlController>();
    
    /**
     * getController singleton
     * @param context (only for Android)
     * @param config type CONFIG
     * @param callback implementing ISeqlCallBack
     * @param File config file (XML format, if null, config.xml must be found in Java resources or Android assets directory) 
     * @param parameter String (WolfHCE inherited class full name or AppSignature for IDGo800)
     * @return ISeqlController (the appropriate controller according CONFIG type)
     * @throws ClassNotFoundException
     * @throws NoSuchMethodException
     * @throws InstantiationException
     * @throws IllegalAccessException
     * @throws InvocationTargetException
     */
    public static ISeqlController getController(Object context, 
    											CONFIG config, 
    											ISeqlCallBack callback, 
    											File configFile, 
    											String parameter) 
    											throws Exception 
    {
    	if (instance == null) 
    	{
    		instance = new SeqlController();
    	}
    	
        ISeqlController ctrl = controllers.get(context);
        
        if (ctrl == null)
        {
        	try 
        	{
        		ctrl = instanciateController(context, config, callback, configFile, parameter);
        	} 
        	catch (Exception e) 
        	{
        		throw e;
        	}
        }
        controllers.put(context, ctrl);
        return ctrl;
    }
    
    /**
	 * Private constructor SeqlController
	 */
	private SeqlController() {
	}

	/**
	 * instanciateController (private)
	 * @param context object
	 * @param config
	 * @param callback
	 * @param file 
	 * @param parameter
	 * @return ISeqlController
	 * @throws ClassNotFoundException
	 * @throws NoSuchMethodException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws InvocationTargetException
	 * @throws IOException
	 */
	private static ISeqlController instanciateController(Object context, CONFIG config, 
														ISeqlCallBack callback, 
														File file,
														String parameter) 
														throws 	ClassNotFoundException, 
																NoSuchMethodException, 
																InstantiationException, 
																IllegalAccessException, 
																InvocationTargetException, 
																Exception
	{
		try 
		{
			Class<?> cla = null;
			
			if (config==CONFIG.ANDROID_OMAPI) 
			{
				cla = Class.forName("org.mbds.wolf.android.omapi.SeqlOmapiController");
			} 
			else if (config==CONFIG.ANDROID_HCE) 
			{
				cla = Class.forName("org.mbds.wolf.android.hce.SeqlHceController");
			} 
			else if (config==CONFIG.PCSC_READER) 
			{
				cla = Class.forName("org.mbds.wolf.java.pcsc.SeqlSmartCardIOController");
			} 
			else if (config==CONFIG.ANDROID_IDGO800) 
			{
				cla = Class.forName("org.mbds.wolf.android.idgo800.SeqlIDGo800Controller");
			} 
			else 
			{
				// Not yet implemented
				throw new ClassNotFoundException();
			}
			
			if (parameter==null) 
			{
				if (file==null)
				{
					Constructor<?> cons = cla.getConstructor(Object.class, ISeqlCallBack.class);
					return (ISeqlController) cons.newInstance(context, callback);
				}
				else
				{
					Constructor<?> cons = cla.getConstructor(Object.class, ISeqlCallBack.class, File.class);
					return (ISeqlController) cons.newInstance(context, callback, file);
				}
			} 
			else 
			{
				if (file==null)
				{
					Constructor<?> cons = cla.getConstructor(Object.class, ISeqlCallBack.class, String.class);
					return (ISeqlController) cons.newInstance(context, callback, parameter);
				}
				else
				{
					Constructor<?> cons = cla.getConstructor(Object.class, ISeqlCallBack.class, File.class, String.class);
					return (ISeqlController) cons.newInstance(context, callback, file, parameter);
				}
			}
		} 
		catch (ClassNotFoundException e) 
		{
			e.printStackTrace();
			throw e;
		} 
		catch (NoSuchMethodException e) 
		{
			e.printStackTrace();
			throw e;
		} 
		catch (InstantiationException e) 
		{
			e.printStackTrace();
			throw e;
		} 
		catch (IllegalAccessException e) 
		{
			e.printStackTrace();
			throw e;
		} 
		catch (IllegalArgumentException e) 
		{
			e.printStackTrace();
			throw e;
		} 
		catch (InvocationTargetException e) 
		{
			e.printStackTrace();
			throw e;
		}
		catch (Exception e) 
		{
			e.printStackTrace();
			throw e;
		}
	}

}
